View Javadoc

1   // SemiConservative.java, created Aug 3, 2004 4:18:21 AM by joewhaley
2   // Copyright (C) 2004 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Allocator;
5   
6   import joeq.Class.PrimordialClassLoader;
7   import joeq.Class.jq_Class;
8   import joeq.Class.jq_StaticField;
9   import joeq.Class.jq_Type;
10  import joeq.Memory.Address;
11  import joeq.Memory.CodeAddress;
12  import joeq.Memory.HeapAddress;
13  import joeq.Memory.StackAddress;
14  import joeq.Runtime.Debug;
15  import joeq.Runtime.Unsafe;
16  import joeq.Scheduler.jq_NativeThread;
17  import joeq.Scheduler.jq_RegisterState;
18  import joeq.Scheduler.jq_Thread;
19  import joeq.Scheduler.jq_ThreadQueue;
20  
21  /***
22   * SemiConservative
23   * 
24   * @author John Whaley
25   * @version $Id: SemiConservative.java 1869 2004-08-09 08:22:27Z joewhaley $
26   */
27  public abstract class SemiConservative {
28      
29      public static void collect() {
30          if (true) Debug.writeln("Starting collection.");
31          
32          jq_Thread t = Unsafe.getThreadBlock();
33          t.disableThreadSwitch();
34          
35          jq_NativeThread.suspendAllThreads();
36          
37          if (true) Debug.writeln("Threads suspended.");
38          SimpleAllocator s = (SimpleAllocator) DefaultHeapAllocator.def();
39          if (true) Debug.writeln("--> Marking roots.");
40          scanRoots();
41          if (true) Debug.writeln("--> Marking queue.");
42          s.scanGCQueue();
43          if (true) Debug.writeln("--> Sweeping.");
44          s.sweep();
45          
46          if (true) Debug.writeln("Resuming threads.");
47          jq_NativeThread.resumeAllThreads();
48          
49          t.enableThreadSwitch();
50      }
51      
52      public static void scanRoots() {
53          scanStatics();
54          scanAllThreads();
55      }
56      
57      /***
58       * Scan static variables for object references.
59       */
60      public static void scanStatics() {
61          // todo: other classloaders?
62          jq_Type[] types = PrimordialClassLoader.loader.getAllTypes();
63          int num = PrimordialClassLoader.loader.getNumTypes();
64          for (int i = 0; i < num; ++i) {
65              Object o = types[i];
66              if (o instanceof jq_Class) {
67                  jq_Class c = (jq_Class) o;
68                  if (c.isSFInitialized()) {
69                      jq_StaticField[] sfs = c.getDeclaredStaticFields();
70                      for (int j=0; j<sfs.length; ++j) {
71                          jq_StaticField sf = sfs[j];
72                          jq_Type t = sf.getType();
73                          if (t.isReferenceType() && !t.isAddressType()) {
74                              if (SimpleAllocator.TRACE_GC) {
75                                  Debug.write(sf.getDeclaringClass().getDesc());
76                                  Debug.write(" ");
77                                  Debug.writeln(sf.getName());
78                              }
79                              HeapAddress a = sf.getAddress();
80                              DefaultHeapAllocator.processObjectReference(a);
81                          }
82                      }
83                  }
84              }
85          }
86      }
87      
88      public static void scanAllThreads() {
89          if (jq_NativeThread.allNativeThreadsInitialized()) {
90              for (int i = 0; i < jq_NativeThread.native_threads.length; ++i) {
91                  jq_NativeThread nt = jq_NativeThread.native_threads[i];
92                  if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning native thread ", i);
93                  scanQueuedThreads(nt);
94                  //addObject(nt, b);
95              }
96          } else {
97              jq_NativeThread nt = Unsafe.getThreadBlock().getNativeThread();
98              if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning initial native thread");
99              scanQueuedThreads(nt);
100         }
101         scanCurrentThreadStack(3);
102     }
103     
104     public static void scanQueuedThreads(jq_NativeThread nt) {
105         for (int i = 0; i < jq_NativeThread.NUM_OF_QUEUES; ++i) {
106             if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning thread queue ", i);
107             scanThreadQueue(nt.getReadyQueue(i));
108         }
109         if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning idle queue");
110         scanThreadQueue(nt.getIdleQueue());
111         if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning transfer queue");
112         scanThreadQueue(nt.getTransferQueue());
113     }
114     
115     public static void scanThreadQueue(jq_ThreadQueue q) {
116         jq_Thread t = q.peek();
117         while (t != null) {
118             scanThreadStack(t);
119             //addObject(t);
120             t = t.getNext();
121         }
122     }
123     
124     public static void scanCurrentThreadStack(int skip) {
125         if (SimpleAllocator.TRACE_GC) Debug.writeln("Scanning current thread stack");
126         StackAddress fp = StackAddress.getBasePointer();
127         StackAddress sp = StackAddress.getStackPointer();
128         CodeAddress ip = (CodeAddress) fp.offset(HeapAddress.size()).peek();
129         while (!fp.isNull()) {
130             if (SimpleAllocator.TRACE_GC) {
131                 Debug.write("Scanning stack frame fp=", fp);
132                 Debug.write(" sp=", sp);
133                 Debug.writeln(" ip=", ip);
134             }
135             if (--skip < 0) {
136                 while (fp.difference(sp) > 0) {
137                     if (SimpleAllocator.TRACE_GC) {
138                         Debug.write("sp: ", sp);
139                         Debug.writeln("  ", sp.peek());
140                     }
141                     addConservativeAddress(sp);
142                     sp = (StackAddress) sp.offset(HeapAddress.size());
143                 }
144             } else {
145                 if (SimpleAllocator.TRACE_GC) Debug.writeln("Skipping this frame.");
146             }
147             ip = (CodeAddress) fp.offset(HeapAddress.size()).peek();
148             sp = fp;
149             fp = (StackAddress) fp.peek();
150         }
151     }
152     
153     public static void scanThreadStack(jq_Thread t) {
154         jq_RegisterState s = t.getRegisterState();
155         StackAddress fp = s.getEbp();
156         CodeAddress ip = s.getEip();
157         StackAddress sp = s.getEsp();
158         while (!fp.isNull()) {
159             while (fp.difference(sp) > 0) {
160                 addConservativeAddress(sp);
161                 sp = (StackAddress) sp.offset(HeapAddress.size());
162             }
163             ip = (CodeAddress) fp.offset(HeapAddress.size()).peek();
164             sp = fp;
165             fp = (StackAddress) fp.peek();
166         }
167     }
168     
169     public static void addConservativeAddress(Address a) {
170         DefaultHeapAllocator.processPossibleObjectReference(a);
171     }
172     
173 }